package org.springframework.core.annotation;

import lombok.Builder;
import org.springframework.util.AliasUtils;
import org.springframework.util.MethodKey;

import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.NoSuchElementException;

@Builder
public class TypeMappedAnnotation<A extends Annotation> implements MergedAnnotation<A>, InvocationHandler {

    private AnnotationTypeMappings.MappingContext mappingContext;

    static <A extends Annotation> TypeMappedAnnotation<A> of() {

        return new TypeMappedAnnotation<>(null);
    }

    @Override
    public A synthesize() throws NoSuchElementException {
        return createProxy();
    }

    private A createProxy() {
        Class<A> annotationType = getType();
        ClassLoader classLoader = annotationType.getClassLoader();
        Class<?>[] interfaces = new Class<?>[]{annotationType};
        return (A) Proxy.newProxyInstance(classLoader, interfaces, this);
    }

    private Class<A> getType() {
        return (Class<A>) this.mappingContext.getAnnotation().annotationType();
    }

    @Override
    public Object invoke(Object proxy,
                         Method method,
                         Object[] args) throws Throwable {
        AnnotationTypeMappings mappings = mappingContext.getMappings();
        MethodKey methodKey = MethodKey.of(method);

        for (AliasUtils.AliasChain<MethodKey> aliasChain : mappings.getAllAliasChains()) {
            if (aliasChain.getElements().contains(methodKey)) {
                return aliasChain.getValueSupplier().get();
            }
        }

        return null;
    }
}
